package com.cipe.cmrs.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.cipe.cmrs.bean.LinkBean;
import com.cipe.cmrs.bean.LinkRoleEntryBean;
import com.cipe.cmrs.model.Role;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.model.ref.Link;
import com.cipe.cmrs.service.LinkService;
import com.cipe.cmrs.service.RoleService;
import com.cipe.cmrs.service.ref.BaseRefService;
import com.cipe.cmrs.util.UserUtil;

@Service
public class LinkServiceImpl extends BaseRefService implements LinkService {
	
	@Autowired
	private ConversionService conversionService;
	
	
	@Autowired RoleService roleService;
	
    @Transactional(propagation = Propagation.NEVER)
    @SuppressWarnings("unchecked")
    public Map<String, List> getRoleManagementData() {        	
    	Map<String, List> rmbData = new HashMap<String, List>();
    	List<LinkRoleEntryBean> checkedRoleList = new ArrayList<LinkRoleEntryBean>();
    	List<LinkBean> linkBeanList = new ArrayList<LinkBean>();
    	List<Role> allRoles = roleService.findAll();
    	
    	List<Link> links = (List<Link>) findAllByType(Link.class);    	
    	LinkBean bean = null;
    	LinkRoleEntryBean lreb = null;
    	
    	for (Link link : links) {    		
    		bean = new LinkBean(link.getId(), link.getName());
    		List<LinkRoleEntryBean> linkBeanRoleEntryList = bean.getRolesEntryList();
    		    		    		
    		Set<Role> linkRoles = link.getRoles();
    		
    		for (Role role : allRoles) {
    			if(linkRoles.contains(role)){
    				lreb = new LinkRoleEntryBean(role.getId(), link.getId(), Boolean.TRUE);
    				checkedRoleList.add(lreb);    				
    			}else{
    				lreb = new LinkRoleEntryBean(role.getId(), link.getId(), Boolean.FALSE);
    			}
    			linkBeanRoleEntryList.add(lreb);
    		}
    		linkBeanList.add(bean);
		}
    	rmbData.put("linkBeanList", linkBeanList);
    	rmbData.put("checkedRoleList", checkedRoleList);
		return rmbData;
	}
    
    public List<LinkRoleEntryBean> saveLinkRoles(Map<Integer, List<Integer>> linkRoles, Integer userId){
		User user = UserUtil.INSTANCE.getCurrentUser();
		
		Set<Integer> linkIds = linkRoles.keySet();
		for (Integer linkId : linkIds) {
	    	boolean hasChanges = false;
			
			Link dbLink = (Link)findById(linkId, Link.class);
			Set<Role> dbLinkRoles = dbLink.getRoles();
			List<Integer> roleIds = linkRoles.get(linkId);
			
			// util methode return two list one for add the second one for removing entities from table.
	        List<List<Role>> dataList = getLinkAddOrRemoveRoleList(dbLinkRoles, roleIds);
	        List<Role> linkAddRoleList = dataList.get(0); 
	    	List<Role> linkRemoveRoleList = dataList.get(1);

	    	if(linkRemoveRoleList.size() > 0){
	    		dbLinkRoles.removeAll(linkRemoveRoleList);
	    		hasChanges = true;
	    	}	    	
	    	if(linkAddRoleList.size() > 0){
	    		dbLinkRoles.addAll(linkAddRoleList);
	    		hasChanges = true;
	    	}
	    	// execute update only when any roles was added or removed.
	    	if(hasChanges){
	    		update(dbLink);
	    	}			
		}
	   	return null;
    }
    
    @SuppressWarnings("unused")
	private List<List<Role>> getLinkAddOrRemoveRoleList(Set<Role> dbLinkRoles, List<Integer> roleIds){
    	List<Role> linkRoleAddList = new ArrayList<Role>(); 
    	List<Role> linkRoleRemoveList = new ArrayList<Role>();

    	// adding Link Role which must be remove.
    	for (Role dbLinkRole : dbLinkRoles) {
			if(!roleIds.contains(dbLinkRole.getId())){
				linkRoleRemoveList.add(dbLinkRole);
			}			
		}    	
    	// adding Link Role which must be add.
    	for (Integer roleId : roleIds) {
    		Role linkRole = roleService.findById(roleId);
			if(!dbLinkRoles.contains(linkRole)){
				linkRoleAddList.add(linkRole);		
			}
		}
        
        List<List<Role>> addAndRemoveList = new ArrayList<List<Role>>();
        addAndRemoveList.add(linkRoleAddList);
        addAndRemoveList.add(linkRoleRemoveList);

    	return addAndRemoveList;
    }
}
